/**
 * 币安K线数据同步到增强表脚本
 * 
 * 该脚本从币安API获取5分钟K线数据，合成多个周期K线(10m, 30m, 1h, 1d)，并将其保存到对应的增强版K线表中
 * 支持增量同步和数据完整性检查
 */

const mysql = require('mysql2/promise');
const axios = require('axios');
const fs = require('fs');
const path = require('path');

// 数据库连接
const pool = mysql.createPool({
    host: '182.160.6.140',
    user: 'root',
    password: 'BinanceRoot2023',
    database: 'binance_klines',
    waitForConnections: true,
    connectionLimit: 10,
    queueLimit: 0
});

// 币安API基础URL
const BINANCE_API_BASE = 'https://api.binance.com/api/v3';

// 要同步的交易对
const SYMBOLS = ['BTCUSDT', 'ETHUSDT'];

// 源数据间隔
const SOURCE_INTERVAL = '5m';  // 从币安API获取的K线间隔

// 目标数据间隔 (通过命令行参数获取)
const args = process.argv.slice(2);
const TARGET_INTERVAL = args[0] || '10m';  // 默认为10m

// 各周期对应的合并因子（以5分钟为基础）
const MERGE_FACTORS = {
    '10m': 2,      // 两个5分钟合成10分钟
    '30m': 6,      // 六个5分钟合成30分钟
    '1h': 12,      // 十二个5分钟合成1小时
    '1d': 288      // 288个5分钟合成1天
};

// 计算三年前的时间戳（毫秒）
const THREE_YEARS_AGO = Date.now() - (3 * 365 * 24 * 60 * 60 * 1000);

// 计算五年前的时间戳（毫秒）
const FIVE_YEARS_AGO = Date.now() - (5 * 365 * 24 * 60 * 60 * 1000);

// 创建当前同步任务的唯一日志文件
const currentDate = new Date().toISOString().replace(/:/g, '').replace(/\..+/, '').replace('T', '_');
const LOG_FILE = path.join(__dirname, '../logs', `sync_enhanced_${TARGET_INTERVAL}_${currentDate.split('_')[0]}.log`);

// 日志输出
function logMessage(message) {
    const timestamp = new Date().toISOString();
    console.log(`[${timestamp}] ${message}`);
    
    // 同时写入日志文件
    const logDir = path.join(__dirname, '../logs');
    if (!fs.existsSync(logDir)) {
        fs.mkdirSync(logDir, { recursive: true });
    }
    
    fs.appendFileSync(LOG_FILE, `[${timestamp}] ${message}\n`);
}

// 主函数
async function main() {
    try {
        logMessage(`开始同步币安历史数据到增强表 ${TARGET_INTERVAL}...`);
        
        // 处理命令行传入的日期参数
        const startDateStr = args[1];
        const endDateStr = args[2]; 
        let manualStartTime = null;
        let manualEndTime = null;
        
        // 如果提供了开始日期参数，解析它
        if (startDateStr) {
            const startDate = new Date(startDateStr);
            if (!isNaN(startDate.getTime())) {
                manualStartTime = startDate.getTime();
                logMessage(`使用命令行指定的开始日期: ${startDate.toISOString()}`);
            } else {
                logMessage(`警告: 无法解析开始日期 "${startDateStr}", 将使用默认值`);
            }
        }
        
        // 如果提供了结束日期参数，解析它
        if (endDateStr) {
            const endDate = new Date(endDateStr);
            if (!isNaN(endDate.getTime())) {
                manualEndTime = endDate.getTime();
                logMessage(`使用命令行指定的结束日期: ${endDate.toISOString()}`);
            } else {
                logMessage(`警告: 无法解析结束日期 "${endDateStr}", 将使用默认值`);
            }
        }
        
        for (const symbol of SYMBOLS) {
            logMessage(`\n处理 ${symbol} 的数据...`);
            
            // 获取最早需要同步的时间戳
            let startTime = manualStartTime || FIVE_YEARS_AGO;
            
            // 如果没有手动指定开始时间，尝试获取该周期已存在的最新数据时间戳
            if (!manualStartTime) {
                const latestTime = await getLatestKlineTime(symbol, TARGET_INTERVAL);
                // 如果有已同步的数据，从最后同步时间+1开始
                if (latestTime) {
                    startTime = latestTime + 1;
                }
            }
            
            const endTime = manualEndTime || Date.now();
            
            logMessage(`\n开始同步 ${symbol} ${TARGET_INTERVAL} 数据，时间范围: ${new Date(startTime).toISOString()} 到 ${new Date(endTime).toISOString()}`);
            
            // 同步数据
            await syncKlineData(symbol, TARGET_INTERVAL, startTime, endTime);
            
            // 查询当前数据状态
            await checkDataStatus(symbol, TARGET_INTERVAL);
            
            // 记录同步历史
            await updateSyncHistory(symbol, TARGET_INTERVAL, endTime);
        }
        
        logMessage(`\n${TARGET_INTERVAL} 数据同步完成! 可以开始使用增强表进行统计分析了`);
    } catch (error) {
        logMessage(`同步过程出错: ${error.message}`);
        console.error(error);
    } finally {
        // 关闭连接池
        await pool.end();
    }
}

// 获取增强表中已存在的最新数据时间戳
async function getLatestKlineTime(symbol, interval) {
    try {
        const tableName = getEnhancedTableName(interval);
        const [rows] = await pool.query(
            `SELECT MAX(open_time) as latest_time FROM ${tableName} WHERE symbol = ?`,
            [symbol]
        );
        
        return rows[0].latest_time || null;
    } catch (error) {
        logMessage(`获取 ${symbol} ${interval} 最新数据时间戳失败: ${error.message}`);
        return null;
    }
}

// 更新同步历史记录
async function updateSyncHistory(symbol, interval, syncTime) {
    try {
        const tableName = getEnhancedTableName(interval);
        
        // 获取当前记录数
        const [countResult] = await pool.query(
            `SELECT COUNT(*) as count FROM ${tableName} WHERE symbol = ?`,
            [symbol]
        );
        
        const recordsCount = countResult[0].count || 0;
        
        // 更新或插入同步历史
        await pool.query(
            `INSERT INTO sync_history (symbol, \`interval\`, last_sync_time, records_count, sync_status) 
             VALUES (?, ?, ?, ?, 'completed') 
             ON DUPLICATE KEY UPDATE 
             last_sync_time = VALUES(last_sync_time), 
             records_count = VALUES(records_count),
             sync_status = VALUES(sync_status),
             updated_at = NOW()`,
            [symbol, interval, syncTime, recordsCount]
        );
        
        logMessage(`更新 ${symbol} ${interval} 同步历史记录，最后同步时间: ${new Date(syncTime).toISOString()}, 总记录数: ${recordsCount}`);
    } catch (error) {
        logMessage(`更新同步历史失败: ${error.message}`);
    }
}

// 获取对应的增强表名
function getEnhancedTableName(interval) {
    if (interval === '1h' || interval === '1d') {
        return `kline_${interval}_enhanced`;
    }
    // 对于如10m, 30m这样的间隔，需要去掉单位'm'
    return `kline_${interval}_enhanced`;
}

// 同步K线数据
async function syncKlineData(symbol, targetInterval, startTime, endTime) {
    try {
        const batchSize = 1000; // 币安API一次最多返回1000条
        let totalSynced = 0;
        
        // 对1d周期使用特殊的按月同步逻辑
        if (targetInterval === '1d') {
            logMessage(`使用按月同步逻辑同步日K线数据...`);
            
            // 计算开始月份和结束月份
            const startDate = new Date(startTime);
            const endDate = new Date(endTime);
            
            // 设置为月初（使用开始日期的年月）
            const currentMonth = new Date(startDate.getFullYear(), startDate.getMonth(), 1);
            
            // 按月循环处理
            while (currentMonth < endDate) {
                // 计算当月的开始和结束时间
                const monthStart = Math.max(currentMonth.getTime(), startTime);
                const nextMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1);
                const monthEnd = Math.min(nextMonth.getTime(), endTime);
                
                const yearMonthStr = `${currentMonth.getFullYear()}-${String(currentMonth.getMonth() + 1).padStart(2, '0')}`;
                logMessage(`获取 ${symbol} 1d 数据：${yearMonthStr}月，时间范围: ${new Date(monthStart).toISOString()} 到 ${new Date(monthEnd).toISOString()}`);
                
                // 一次性获取整月的日K线数据
                const klinesData = await fetchKlines(symbol, targetInterval, monthStart, monthEnd);
                
                if (klinesData && klinesData.length > 0) {
                    logMessage(`获取到 ${klinesData.length} 条 ${targetInterval} K线数据`);
                    
                    // 计算时间维度属性
                    const enrichedKlines = calculateTimeAttributes(klinesData);
                    
                    // 插入到对应的增强表
                    const inserted = await batchInsertEnhancedKlines(symbol, enrichedKlines, targetInterval);
                    totalSynced += inserted;
                    
                    logMessage(`插入 ${inserted}/${enrichedKlines.length} 条 ${targetInterval} K线数据，累计: ${totalSynced}`);
                } else {
                    logMessage(`${yearMonthStr}月没有获取到数据`);
                }
                
                // 移动到下一个月
                currentMonth.setMonth(currentMonth.getMonth() + 1);
                
                // 添加延迟避免API限制
                await new Promise(resolve => setTimeout(resolve, 300));
            }
            
            return totalSynced;
        }
        
        // 其他周期（非1d）使用常规逻辑
        let currentStartTime = startTime;
        
        // 确定API请求的间隔，只有10m需要从5m合成，其他直接获取
        const apiInterval = targetInterval === '10m' ? SOURCE_INTERVAL : targetInterval;
        
        while (currentStartTime < endTime) {
            // 设置批次大小
            let effectiveBatchSize = batchSize;
            
            // 只有10m需要考虑合并因子
            if (targetInterval === '10m') {
                const mergeFactor = MERGE_FACTORS[targetInterval] || 1;
                effectiveBatchSize = Math.floor(batchSize / mergeFactor) * mergeFactor;
            }
            
            const batchEndTime = Math.min(
                currentStartTime + (effectiveBatchSize * getIntervalMilliseconds(apiInterval)),
                endTime
            );
            
            logMessage(`获取 ${symbol} ${apiInterval} 数据从 ${new Date(currentStartTime).toISOString()} 到 ${new Date(batchEndTime).toISOString()}`);
            
            // 从币安API获取K线数据
            const klinesData = await fetchKlines(symbol, apiInterval, currentStartTime, batchEndTime);
            
            if (klinesData && klinesData.length > 0) {
                logMessage(`获取到 ${klinesData.length} 条 ${apiInterval} K线数据`);
                
                let processedKlines = [];
                
                // 10m需要合成，其他周期直接使用
                if (targetInterval === '10m') {
                    // 合成10分钟K线
                    processedKlines = mergeKlinesToLargerTimeframe(symbol, klinesData, targetInterval);
                } else {
                    // 直接使用API返回的数据
                    processedKlines = klinesData;
                }
                
                if (processedKlines.length > 0) {
                    // 计算时间维度属性
                    const enrichedKlines = calculateTimeAttributes(processedKlines);
                    
                    // 插入到对应的增强表
                    const inserted = await batchInsertEnhancedKlines(symbol, enrichedKlines, targetInterval);
                    totalSynced += inserted;
                    
                    if (targetInterval === '10m') {
                        logMessage(`合成并插入 ${inserted}/${enrichedKlines.length} 条 ${targetInterval} K线数据，累计: ${totalSynced}`);
                    } else {
                        logMessage(`插入 ${inserted}/${enrichedKlines.length} 条 ${targetInterval} K线数据，累计: ${totalSynced}`);
                    }
                }
                
                // 更新下一批次的起始时间
                const lastTimestamp = parseInt(klinesData[klinesData.length - 1][0]);
                currentStartTime = lastTimestamp + getIntervalMilliseconds(apiInterval);
            } else {
                // 如果没有获取到数据，增加起始时间继续查询
                currentStartTime = batchEndTime;
                logMessage('未获取到数据，跳到下一个时间段');
            }
            
            // 添加延迟避免API限制
            await new Promise(resolve => setTimeout(resolve, 300));
        }
        
        return totalSynced;
    } catch (error) {
        logMessage(`同步 ${symbol} ${targetInterval} 数据失败: ${error.message}`);
        throw error;
    }
}

// 将5分钟K线合并为目标周期K线
function mergeKlinesToLargerTimeframe(symbol, klines5m, targetInterval) {
    const mergedKlines = [];
    const mergeFactor = MERGE_FACTORS[targetInterval] || 2; // 默认为10分钟
    
    // 确保K线数据按时间排序
    klines5m.sort((a, b) => parseInt(a[0]) - parseInt(b[0]));
    
    // 临时存储需要合并的K线
    let accumulator = [];
    
    // 对齐到目标周期的起始时刻
    for (let i = 0; i < klines5m.length; i++) {
        const kline = klines5m[i];
        const openTime = parseInt(kline[0]);
        const openDate = new Date(openTime);
        
        // 检查时间是否对齐到目标周期
        let isAligned = false;
        
        if (targetInterval === '10m') {
            // 10分钟周期起始时间：分钟能被10整除
            isAligned = openDate.getUTCMinutes() % 10 === 0;
        } else if (targetInterval === '30m') {
            // 30分钟周期起始时间：分钟为0, 30
            isAligned = openDate.getUTCMinutes() % 30 === 0;
        } else if (targetInterval === '1h') {
            // 1小时周期起始时间：分钟为0
            isAligned = openDate.getUTCMinutes() === 0;
        } else if (targetInterval === '1d') {
            // 1天周期起始时间：时分为00:00
            isAligned = openDate.getUTCHours() === 0 && openDate.getUTCMinutes() === 0;
        }
        
        if (isAligned) {
            // 如果已有累积的K线，且数量足够，则合并它们
            if (accumulator.length === mergeFactor) {
                const mergedKline = mergeKlineGroup(accumulator);
                mergedKlines.push(mergedKline);
            } else if (accumulator.length > 0) {
                logMessage(`警告: K线组数量不足 ${mergeFactor}，丢弃不完整的周期`);
            }
            
            // 开始新的累积
            accumulator = [kline];
        } else if (accumulator.length > 0) {
            // 如果已经开始累积，继续添加K线
            accumulator.push(kline);
        }
        
        // 当累积的K线达到目标合并数量时，执行合并
        if (accumulator.length === mergeFactor) {
            const mergedKline = mergeKlineGroup(accumulator);
            mergedKlines.push(mergedKline);
            accumulator = []; // 清空累积器，等待下一个对齐周期
        }
    }
    
    if (mergedKlines.length === 0) {
        logMessage(`警告: 没有合成任何 ${targetInterval} K线，可能是5分钟K线不连续或没有按目标周期对齐`);
    } else {
        logMessage(`成功合成 ${mergedKlines.length} 条 ${targetInterval} K线`);
    }
    
    return mergedKlines;
}

// 合并一组K线为一个更大周期的K线
function mergeKlineGroup(klines) {
    if (!klines || klines.length === 0) return null;
    
    // 使用第一个K线的开盘时间和开盘价
    const firstKline = klines[0];
    // 使用最后一个K线的收盘时间和收盘价
    const lastKline = klines[klines.length - 1];
    
    // 初始化最高价和最低价
    let highPrice = parseFloat(firstKline[2]);
    let lowPrice = parseFloat(firstKline[3]);
    
    // 累积成交量、成交额、成交笔数等
    let volume = 0;
    let quoteVolume = 0;
    let tradesCount = 0;
    let takerBuyVolume = 0;
    let takerBuyQuoteVolume = 0;
    
    // 遍历所有K线，计算最高价、最低价和累积值
    for (const kline of klines) {
        const high = parseFloat(kline[2]);
        const low = parseFloat(kline[3]);
        
        // 更新最高价和最低价
        if (high > highPrice) highPrice = high;
        if (low < lowPrice) lowPrice = low;
        
        // 累积成交量和成交额
        volume += parseFloat(kline[5]);
        quoteVolume += parseFloat(kline[7]);
        tradesCount += parseInt(kline[8]);
        takerBuyVolume += parseFloat(kline[9]);
        takerBuyQuoteVolume += parseFloat(kline[10]);
    }
    
    // 构建合并后的K线
    return [
        firstKline[0],        // 开盘时间 - 使用第一个K线的开盘时间
        firstKline[1],        // 开盘价 - 使用第一个K线的开盘价
        highPrice.toString(), // 最高价 - 所有K线中的最高价
        lowPrice.toString(),  // 最低价 - 所有K线中的最低价
        lastKline[4],         // 收盘价 - 使用最后一个K线的收盘价
        volume.toString(),    // 成交量
        lastKline[6],         // 收盘时间 - 使用最后一个K线的收盘时间
        quoteVolume.toString(), // 成交额
        tradesCount.toString(), // 成交笔数
        takerBuyVolume.toString(), // 主动买入成交量
        takerBuyQuoteVolume.toString() // 主动买入成交额
    ];
}

// 计算时间属性
function calculateTimeAttributes(klines) {
    return klines.map(kline => {
        const openTime = parseInt(kline[0]);
        const openDate = new Date(openTime);
        
        // 计算星期几 (0-6, 0=周日)
        const dayOfWeek = openDate.getUTCDay();
        
        // 计算小时 (0-23)
        const hourOfDay = openDate.getUTCHours();
        
        // 判断是否是周末 (周六=6, 周日=0)
        const isWeekend = dayOfWeek === 0 || dayOfWeek === 6 ? 1 : 0;
        
        // 判断美股是否开盘 (周一至周五 9:30-16:00 EST)
        // 需要将UTC时间转换为EST时间 (UTC-4 夏令时，UTC-5 冬令时)
        // 简化处理：我们假设UTC-4
        const estHour = (hourOfDay - 4 + 24) % 24; // 转换为EST时间
        const isUsMarketOpen = (dayOfWeek >= 1 && dayOfWeek <= 5) && (estHour >= 9 && estHour < 16) ? 1 : 0;
        
        // 返回添加了时间维度属性的K线
        return {
            ...kline,
            dayOfWeek,
            hourOfDay,
            isWeekend,
            isUsMarketOpen
        };
    });
}

// 从币安API获取K线数据
async function fetchKlines(symbol, interval, startTime, endTime) {
    let retries = 3;
    let lastError = null;
    
    while (retries > 0) {
        try {
            const url = `${BINANCE_API_BASE}/klines?symbol=${symbol}&interval=${interval}&startTime=${startTime}&endTime=${endTime}&limit=1000`;
            logMessage(`API请求: ${url}`);
            
            const response = await axios.get(url, {
                headers: {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
                },
                timeout: 30000
            });
            
            if (response.data && response.data.length > 0) {
                return response.data;
            } else {
                logMessage(`API返回空数据: ${JSON.stringify(response.data)}`);
                return [];
            }
        } catch (error) {
            lastError = error;
            logMessage(`API请求失败 (重试 ${3 - retries + 1}/3): ${error.message}`);
            if (error.response) {
                logMessage(`错误状态码: ${error.response.status}`);
                if (error.response.data) {
                    logMessage(`错误详情: ${JSON.stringify(error.response.data)}`);
                }
            }
            
            retries--;
            
            if (retries > 0) {
                // 指数退避策略
                const delay = (3 - retries) * 2000;
                logMessage(`等待 ${delay}ms 后重试...`);
                await new Promise(resolve => setTimeout(resolve, delay));
            } else {
                throw new Error(`获取K线数据失败: ${lastError.message}`);
            }
        }
    }
    
    return [];
}

// 批量插入K线数据到增强表
async function batchInsertEnhancedKlines(symbol, klines, interval) {
    if (!klines || klines.length === 0) return 0;
    
    try {
        // 获取表名
        const tableName = getEnhancedTableName(interval);
        
        // 准备插入的数据
        const values = klines.map(k => [
            symbol,
            parseInt(k[0]),                        // open_time
            parseInt(k[6]),                        // close_time
            k[1],                                  // open_price
            k[2],                                  // high_price
            k[3],                                  // low_price
            k[4],                                  // close_price
            k[5],                                  // volume
            k[7],                                  // quote_volume
            parseInt(k[8]),                        // trades_count
            k[9],                                  // taker_buy_volume
            k[10],                                 // taker_buy_quote_volume
            k.isUsMarketOpen || 0,                 // is_us_market_open
            k.dayOfWeek || 0,                      // day_of_week
            k.hourOfDay || 0                       // hour_of_day
        ]);
        
        // 构建INSERT IGNORE语句，避免重复数据
        const sql = `INSERT IGNORE INTO ${tableName} 
                    (symbol, open_time, close_time, open_price, high_price, low_price, 
                     close_price, volume, quote_volume, trades_count, taker_buy_volume, 
                     taker_buy_quote_volume, is_us_market_open, day_of_week, hour_of_day) 
                    VALUES ?`;
        
        const [result] = await pool.query(sql, [values]);
        return result.affectedRows;
    } catch (error) {
        logMessage(`批量插入 ${interval} 数据失败: ${error.message}`);
        return 0;
    }
}

// 检查数据状态
async function checkDataStatus(symbol, interval) {
    try {
        const tableName = getEnhancedTableName(interval);
        
        // 查询数据总量
        const [totalResult] = await pool.query(
            `SELECT COUNT(*) as total FROM ${tableName} WHERE symbol = ?`,
            [symbol]
        );
        
        // 查询三年内数据量
        const [recentResult] = await pool.query(
            `SELECT COUNT(*) as recent FROM ${tableName} WHERE symbol = ? AND open_time >= ?`,
            [symbol, THREE_YEARS_AGO]
        );
        
        // 查询最早和最新的数据时间
        const [rangeResult] = await pool.query(
            `SELECT MIN(open_time) as earliest, MAX(open_time) as latest FROM ${tableName} WHERE symbol = ?`,
            [symbol]
        );
        
        logMessage(`\n${symbol} ${interval} 数据状态:`);
        logMessage(`总数据量: ${totalResult[0].total} 条`);
        logMessage(`近三年数据: ${recentResult[0].recent} 条`);
        
        if (rangeResult[0].earliest) {
            logMessage(`数据时间范围: ${new Date(rangeResult[0].earliest).toISOString()} 到 ${new Date(rangeResult[0].latest).toISOString()}`);
        }
        
        // 计算预期每天的记录数
        const recordsPerDay = calculateRecordsPerDay(interval);
        
        // 检查每天的数据完整性
        const [dailyResult] = await pool.query(
            `SELECT DATE(FROM_UNIXTIME(open_time/1000)) as date, 
             COUNT(*) as count 
             FROM ${tableName} 
             WHERE symbol = ? AND open_time >= ?
             GROUP BY date
             HAVING count < ?
             ORDER BY count ASC
             LIMIT 5`,
            [symbol, THREE_YEARS_AGO, recordsPerDay]
        );
        
        if (dailyResult.length > 0) {
            logMessage('\n数据不完整的日期:');
            dailyResult.forEach(row => {
                logMessage(`${row.date}: ${row.count}/${recordsPerDay} 条`);
            });
            
            // 计算理论数据量和缺失比例
            const [expectedResult] = await pool.query(
                `SELECT COUNT(DISTINCT DATE(FROM_UNIXTIME(open_time/1000))) as days,
                 COUNT(*) as actual,
                 COUNT(DISTINCT DATE(FROM_UNIXTIME(open_time/1000))) * ? as expected
                FROM ${tableName} 
                WHERE symbol = ? AND open_time >= ?`,
                [recordsPerDay, symbol, THREE_YEARS_AGO]
            );
            
            if (expectedResult[0].days > 0) {
                const expected = expectedResult[0].expected;
                const actual = expectedResult[0].actual;
                const missing = expected - actual;
                const missingPercent = (missing / expected * 100).toFixed(2);
                
                logMessage(`数据完整性分析: 应有 ${expected} 条，实际 ${actual} 条，缺失 ${missing} 条 (${missingPercent}%)`);
            }
        } else {
            logMessage('所有日期的数据均已完整!');
        }
    } catch (error) {
        logMessage(`检查 ${interval} 数据状态失败: ${error.message}`);
    }
}

// 计算每个周期每天的理论记录数
function calculateRecordsPerDay(interval) {
    switch(interval) {
        case '10m': return 144;  // 24小时 * 6 (每小时10分钟K线数)
        case '30m': return 48;   // 24小时 * 2 (每小时30分钟K线数)
        case '1h': return 24;    // 24小时
        case '1d': return 1;     // 1天1条
        default: return 144;     // 默认按10分钟计算
    }
}

// 获取时间间隔对应的毫秒数
function getIntervalMilliseconds(interval) {
    const unit = interval.slice(-1);
    const value = parseInt(interval.slice(0, -1));
    
    switch (unit) {
        case 'm': return value * 60 * 1000;
        case 'h': return value * 60 * 60 * 1000;
        case 'd': return value * 24 * 60 * 60 * 1000;
        case 'w': return value * 7 * 24 * 60 * 60 * 1000;
        default: return value * 60 * 1000;
    }
}

// 运行主函数
main().catch(error => {
    logMessage(`程序执行错误: ${error.message}`);
    console.error(error);
    process.exit(1);
});